package com.common.utils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.UUID;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;


public class AESUtil {
	/**
	 * 
	 * 基本思路：
	 * 加密： 
	 * 	32位uuid作为密钥
	 * 	将明文与密钥进行AES加密后返回密文
	 *  将密钥拼接在密文前面作为最终的密文。
	 * 解密：
	 * 截取前32位作为解密密钥
	 * 将密文去掉前32位，然后和密钥进行AES解密，得出明文
	 * 
	 * @throws NoSuchAlgorithmException
	 * @throws UnsupportedEncodingException
	 * @throws NoSuchPaddingException
	 * @throws InvalidKeyException
	 * @throws BadPaddingException
	 * @throws IllegalBlockSizeException
	 * 
	 */

	/*
	 * 加密 1.构造密钥生成器 
	 * 2.根据ecnodeRules规则初始化密钥生成器 
	 * 3.产生密钥 
	 * 4.创建和初始化密码器 
	 * 5.内容加密
	 * 6.返回字符串
	 */
	public static String encrypt(String content)
			throws NoSuchAlgorithmException, UnsupportedEncodingException,
			NoSuchPaddingException, InvalidKeyException,
			IllegalBlockSizeException, BadPaddingException {
		String uuid = UUID.randomUUID().toString().toUpperCase(); // 获取UUID并转化为String对象
		String encodeRules = uuid.replace("-", "");// 因为UUID本身为32位只是生成时多了“-”，所以将它们去点就可
		// 1.构造密钥生成器，指定为AES算法,不区分大小写
		KeyGenerator keygen = KeyGenerator.getInstance("AES");
		// 2.根据ecnodeRules规则初始化密钥生成器
		// 生成一个128位的随机源,根据传入的字节数组
		keygen.init(128, new SecureRandom(encodeRules.getBytes("utf-8")));
		// 3.产生原始对称密钥
		SecretKey original_key = keygen.generateKey();
		// 4.获得原始对称密钥的字节数组
		byte[] raw = original_key.getEncoded();
		// 5.根据字节数组生成AES密钥
		SecretKey key = new SecretKeySpec(raw, "AES");
		// 6.根据指定算法AES生成密码器
		Cipher cipher = Cipher.getInstance("AES");
		// 7.初始化密码器，第一个参数为加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作，第二个参数为使用的KEY
		cipher.init(Cipher.ENCRYPT_MODE, key);
		// 8.获取加密内容的字节数组(这里要设置为utf-8)不然内容中如果有中文和英文混合中文就会解密为乱码
		byte[] byte_encode = content.getBytes("utf-8");
		// 9.根据密码器的初始化方式--加密：将数据加密
		byte[] byte_AES = cipher.doFinal(byte_encode);
		// 10.将加密后的数据转换为字符串
		// 这里用Base64Encoder中会找不到包
		// 解决办法：
		// 在项目的Build path中先移除JRE System Library，再添加库JRE System
		// Library，重新编译后就一切正常了。
		
		String AES_encode = new String(Base64.encodeBase64(byte_AES));
		// 11.将uuid与字符串拼接作为密文返回
		return encodeRules + AES_encode;
	}

	/*
	 * 解密 只能解密此AESEncode(String content)方法加密过的密文 解密过程：
	 * 1.同加密1-4步
	 * 2.将加密后的字符串反纺成byte[]数组
	 * 3.将加密内容解密
	 */
	public static String decrypt(String content)
			throws NoSuchAlgorithmException, NoSuchPaddingException,
			InvalidKeyException, IOException, IllegalBlockSizeException,
			BadPaddingException {
		int n = 32;// 密钥固定长度
		String encodeRules = content.substring(0, n);// 根据加密内容获取的密钥
		content = content.substring(n, content.length());// 去掉密钥过后的密文
		// 1.构造密钥生成器，指定为AES算法,不区分大小写
		KeyGenerator keygen = KeyGenerator.getInstance("AES");
		// 2.根据ecnodeRules规则初始化密钥生成器
		// 生成一个128位的随机源,根据传入的字节数组
		keygen.init(128, new SecureRandom(encodeRules.getBytes("utf-8")));
		// 3.产生原始对称密钥
		SecretKey original_key = keygen.generateKey();
		// 4.获得原始对称密钥的字节数组
		byte[] raw = original_key.getEncoded();
		// 5.根据字节数组生成AES密钥
		SecretKey key = new SecretKeySpec(raw, "AES");
		// 6.根据指定算法AES生成密码器
		Cipher cipher = Cipher.getInstance("AES");
		// 7.初始化密码器，第一个参数为加密(Encrypt_mode)或者解密(Decrypt_mode)操作，第二个参数为使用的KEY
		cipher.init(Cipher.DECRYPT_MODE, key);
		// 8.将加密并编码后的内容解码成字节数组
		byte[] byte_content = Base64.decodeBase64(content);
		/*
		 * 解密
		 */
		byte[] byte_decode = cipher.doFinal(byte_content);
		String AES_decode = new String(byte_decode, "utf-8");
		return AES_decode;
	}
}
